﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace JsonCreator
{
    public partial class jsonCreatorForm : Form
    {
        private int mintScrollDirection;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

        private const int WM_VSCROLL = 277; // Vertical scroll
        private const int SB_LINEUP = 0; // Scrolls one line up
        private const int SB_LINEDOWN = 1; // Scrolls one line down

        public jsonCreatorForm()
        {
            InitializeComponent();
            InitializeAuxComponent();
        }

        private void InitializeAuxComponent()
        {
            System.Globalization.CultureInfo cInfo = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            cInfo.NumberFormat.NumberDecimalSeparator = ".";
            cInfo.NumberFormat.NumberGroupSeparator = ",";
            System.Threading.Thread.CurrentThread.CurrentCulture = cInfo;

            foreach (View i in Enum.GetValues(typeof(View)))
                tscbViewMode.Items.Add(i.ToString());
            tscbViewMode.SelectedIndex = 0;
            listView1.View = (View)Enum.Parse(typeof(View), tscbViewMode.Text);

            listView1.LargeImageList = new ImageList();
            listView1.LargeImageList.ImageSize = new Size(128, 128);
            listView1.LargeImageList.ColorDepth = ColorDepth.Depth24Bit;
            listView1.SmallImageList = new ImageList();
            listView1.SmallImageList.ImageSize = new Size(32, 32);
            listView1.SmallImageList.ColorDepth = ColorDepth.Depth24Bit;

            if (Properties.Settings.Default.LastLoadFile != null)
            {
                tsmLoad.DropDownItems.Clear();
                foreach (string s in Properties.Settings.Default.LastLoadFile)
                {
                    ToolStripMenuItem tsi = new ToolStripMenuItem(s, null, tsmLoadRecent_Click);
                    tsmLoad.DropDownItems.Add(tsi);
                }
            }

            if (Properties.Settings.Default.LastSaveFile != null)
            {
                tsmSave.DropDownItems.Clear();
                foreach (string s in Properties.Settings.Default.LastSaveFile)
                {
                    ToolStripMenuItem tsi = new ToolStripMenuItem(s, null, tsmSaveRecent_Click);
                    tsmSave.DropDownItems.Add(tsi);
                }
            }
        }

        private void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            listView1.View = (View)Enum.Parse(typeof(View), tscbViewMode.Text);
        }

        private void tsmLoad_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SetLoadRecent(fbd.SelectedPath);
                LoadAlbum(fbd.SelectedPath);
            }
        }

        private void tsmLoadRecent_Click(object sender, EventArgs e)
        {
            LoadAlbum(sender.ToString());
        }

        private void LoadAlbum(string path)
        {
            tssLabel.Text = "Leggo Json";
            Application.DoEvents();

            jsonManager.LoadData(path);
            PopulateListView(jsonManager.Folder);
        }

        private void tsmSave_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SetSaveRecent(fbd.SelectedPath);
                SaveAlbum(fbd.SelectedPath);
            }
        }

        private void SaveAlbum(string path)
        {
            jsonManager.Clear();
            foreach (ExListViewItem lvi in listView1.Items)
                jsonManager.PutFoto(lvi.myFoto);
            jsonManager.SaveData(path);
        }

        private void tsmSaveRecent_Click(object sender, EventArgs e)
        {
            SaveAlbum(sender.ToString());
        }

        private void tsmExit_Click(object sender, EventArgs e)
        {
            Application.ExitThread();
        }

        private void SetLoadRecent(string folder)
        {
            if (Properties.Settings.Default.LastLoadFile == null)
                Properties.Settings.Default.LastLoadFile = new System.Collections.Specialized.StringCollection();

            if (!Properties.Settings.Default.LastLoadFile.Contains(folder))
            {
                Properties.Settings.Default.LastLoadFile.Insert(0, folder);
                if (Properties.Settings.Default.LastLoadFile.Count > 4)
                    Properties.Settings.Default.LastLoadFile.RemoveAt(4);

                Properties.Settings.Default.Save();
            }
        }

        private void SetSaveRecent(string folder)
        {
            if (Properties.Settings.Default.LastSaveFile == null)
                Properties.Settings.Default.LastSaveFile = new System.Collections.Specialized.StringCollection();

            if (!Properties.Settings.Default.LastSaveFile.Contains(folder))
            {
                Properties.Settings.Default.LastSaveFile.Insert(0, folder);
                if (Properties.Settings.Default.LastSaveFile.Count > 4)
                    Properties.Settings.Default.LastSaveFile.RemoveAt(4);

                Properties.Settings.Default.Save();
            }
        }

        private void PopulateListView(string folder)
        {
            tssProgressBar.Maximum = jsonManager.Album.Count;
            tssProgressBar.Visible = true;
            listView1.SuspendLayout();
            listView1.BeginUpdate();

            int t = 0;
            foreach (JsonCreator.foto myPhoto in jsonManager.Album)
            {
                string file = Path.ChangeExtension(Path.Combine(folder, myPhoto.filename), ".jpg");
                tssLabel.Text = myPhoto.filename;
                tssProgressBar.PerformStep();
                Application.DoEvents();

                using (Image img = Image.FromFile(file))
                {
                    listView1.LargeImageList.Images.Add(myPhoto.filename, img);
                    listView1.SmallImageList.Images.Add(myPhoto.filename, img);
                }
                listView1.Items.Add(CreateItem(t++, myPhoto));
            }

            listView1.EndUpdate();
            listView1.ResumeLayout(true);
            tssProgressBar.Visible = false;
            tssLabel.Text = "Pronto";
        }

        private ListViewItem CreateItem(int t, foto myFoto)
        {
            ExListViewItem lvi = new ExListViewItem(myFoto.filename, myFoto.filename);

            lvi.SubItems.Add(myFoto.title).Name = "title";
            lvi.SubItems.Add(myFoto.comment).Name = "comment";
            lvi.SubItems.Add(myFoto.place).Name = "place";
            lvi.SubItems.Add(myFoto.events).Name = "events";
            lvi.SubItems.Add(myFoto.type).Name = "type";
            lvi.SubItems.Add(myFoto.privates).Name = "privates";
            lvi.SubItems.Add(myFoto.yeardate.ToString()).Name = "yeardate";
            lvi.SubItems.Add(myFoto.stars.ToString()).Name = "stars";
            lvi.SubItems.Add(t.ToString("0000")).Name = "progressive";

            lvi.AddFoto(myFoto);

            Autocomplete(txtTitle, myFoto.title);
            Autocomplete(txtEvent, myFoto.events);
            Autocomplete(txtType, myFoto.type);
            Autocomplete(txtPlace, myFoto.place);

            return lvi;
        }

        private void Autocomplete(ExTextBox txtbox, string text)
        {
            if (!string.IsNullOrEmpty(text) && !txtbox.AutoCompleteCustomSource.Contains(text))
                txtbox.AutoCompleteCustomSource.Add(text);
        }

        private void listView1_DragDrop(object sender, DragEventArgs e)
        {
            Point p = listView1.PointToClient(new Point(e.X, e.Y));
            ExListViewItem lvd = (ExListViewItem)listView1.GetItemAt(p.X, p.Y);
            //ListViewItem lvs = (ExListViewItem)e.Data.GetData(typeof(ExListViewItem));
            if (listView1.SelectedItems.Count > 0)
                MoveFoto(lvd);
        }

        private void listView1_DragOver(object sender, DragEventArgs e)
        {
            Point p = listView1.PointToClient(new Point(e.X, e.Y));
            ExListViewItem lvi = (ExListViewItem)listView1.GetItemAt(p.X, p.Y);

            e.Effect = lvi == null
                        ? DragDropEffects.None
                        : DragDropEffects.Move;

            Debug.WriteLine(p.Y + " " + ClientSize.Height);

            if (p.Y <= 20)
            {
                // getting close to top, ensure previous item is visible
                mintScrollDirection = SB_LINEUP;
                timer1.Enabled = true;
            }
            else if (p.Y >= listView1.Size.Height - 20)
            {
                // getting close to bottom, ensure next item is visible
                mintScrollDirection = SB_LINEDOWN;
                timer1.Enabled = true;
            }
            else
            {
                timer1.Enabled = false;
            }
        }

        private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            listView1.DoDragDrop(e.Item, DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.None);
        }

        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtTitle.Text = string.Empty;
            txtComment.Text = string.Empty;
            txtEvent.Text = string.Empty;
            txtType.Text = string.Empty;
            txtPlace.Text = string.Empty;
            txtPrivate.Text = string.Empty;
            string picture = string.Empty;

            bool firstTime = true;

            foreach (int idx in listView1.SelectedIndices)
            {
                foto myFoto = ((ExListViewItem)listView1.Items[idx]).myFoto;
                txtTitle.Text = txtTitle.Text.MultiAssign(myFoto.title, firstTime);
                txtComment.Text = txtComment.Text.MultiAssign(myFoto.comment, firstTime);
                txtEvent.Text = txtEvent.Text.MultiAssign(myFoto.events, firstTime);
                txtType.Text = txtType.Text.MultiAssign(myFoto.type, firstTime);
                txtPlace.Text = txtPlace.Text.MultiAssign(myFoto.place, firstTime);
                txtPrivate.Text = txtPrivate.Text.MultiAssign(myFoto.privates, firstTime);
                picture = picture.MultiAssign(myFoto.filename, firstTime);
                nudStars.Value = nudStars.Value.MultiAssign((Decimal)myFoto.stars, firstTime);
                firstTime = false;
            }

            pcbPreview.Image = listView1.LargeImageList.Images[picture];
        }

        private void MoveFoto(ExListViewItem lvd)
        {
            int last = -1;
            listView1.BeginUpdate();
            foreach (ExListViewItem lvi in listView1.SelectedItems)
            {
                if (lvi != lvd)
                {
                    listView1.Items.Remove(lvi);
                    int posDest = listView1.Items.IndexOf(lvd);
                    listView1.Items.Insert(posDest, lvi);
                    last = posDest;
                }
            }
            listView1.SelectedItems.Clear();

            View ori = listView1.View;
            listView1.View = listView1.View == View.Details
                                ? View.List
                                : View.Details;
            listView1.View = ori;
            listView1.EndUpdate();
            listView1.Refresh();
            if (last != -1)
                listView1.EnsureVisible(last);
        }

        private void btnStore_Click(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;
            foreach (int idx in listView1.SelectedIndices)
            {
                foto myFoto = ((ExListViewItem)listView1.Items[idx]).myFoto;
                if (txtTitle.textChanged)
                {
                    myFoto.title = txtTitle.Text;
                    listView1.Items[idx].SubItems["title"].Text = txtTitle.Text.NotNullValue();
                }

                if (txtComment.textChanged)
                {
                    myFoto.comment = txtComment.Text;
                    listView1.Items[idx].SubItems["comment"].Text = txtComment.Text.NotNullValue();
                }

                if (txtEvent.textChanged)
                {
                    myFoto.events = txtEvent.Text;
                    listView1.Items[idx].SubItems["events"].Text = txtEvent.Text.NotNullValue();
                }

                if (txtType.textChanged)
                {
                    myFoto.type = txtType.Text;
                    listView1.Items[idx].SubItems["type"].Text = txtType.Text.NotNullValue();
                }

                if (txtPlace.textChanged)
                {
                    myFoto.place = txtPlace.Text;
                    listView1.Items[idx].SubItems["place"].Text = txtPlace.Text.NotNullValue();
                }

                if (txtPrivate.textChanged)
                {
                    myFoto.privates = txtPrivate.Text;
                    listView1.Items[idx].SubItems["privates"].Text = txtPrivate.Text.NotNullValue();
                }

                if (nudStars.valueChanged)
                {
                    myFoto.stars = Convert.ToDouble(nudStars.Value);
                    listView1.Items[idx].SubItems["stars"].Text = nudStars.Value.ToString();
                }

                tssLabel.Text = string.Format("Memorizzo {0}", myFoto.filename);
                Application.DoEvents();
                jsonManager.UpdateFile(myFoto);
            }
            Cursor = Cursors.Default;
            tssLabel.Text = "Pronto";
        }

        private void txtTitle_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void txtComment_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void txtPlace_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void txtEvent_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void txtType_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void txtPrivate_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void tsmiDelete_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(string.Format("Sei sicuro di voler cancellare {0} foto", listView1.SelectedItems.Count),
                "Cancellazione", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                foreach (ExListViewItem lvi in listView1.SelectedItems)
                    listView1.Items.Remove(lvi);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            SendMessage(listView1.Handle, WM_VSCROLL, (IntPtr)mintScrollDirection, IntPtr.Zero);
        }

        private void nudStars_LeaveWithChangedText(object sender, EventArgs e)
        {
        }

        private void tsmiUpdateFromExif_Click(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;
            foreach (int idx in listView1.SelectedIndices)
            {
                foto myFoto = ((ExListViewItem)listView1.Items[idx]).myFoto;
                tssLabel.Text = string.Format("aggiorno {0}", myFoto.filename);
                Application.DoEvents();
                jsonManager.UpdateFoto(ref myFoto);
            }
            Cursor = Cursors.Default;
        }
    }

    public static class ExtendedDecimal
    {
        public static Decimal MultiAssign(this Decimal str, Decimal arg0, bool firsttime)
        {
            return firsttime
                    ? arg0
                    : ((str == arg0)
                         ? arg0
                         : 0);
        }
    }

    public static class ExtendedString
    {
        public static string CommaConcact(this string str, string arg0)
        {
            if (str.Length == 0)
                return arg0;

            return string.Concat(str, ", ", arg0);
        }

        public static string NotNullValue(this string str)
        {
            return str == null
                    ? string.Empty
                    : str;
        }

        public static string MultiAssign(this string str, string arg0, bool firsttime)
        {
            return firsttime
                    ? arg0
                    : ((str == arg0)
                         ? arg0
                         : string.Empty);
        }
    }

    public class ExListViewItem : ListViewItem
    {
        public foto myFoto { get; private set; }

        public ExListViewItem(string text, string imageKey)
            : base(text, imageKey)
        {
            myFoto = null;
        }

        public void AddFoto(foto myfoto)
        {
            myFoto = myfoto;
        }
    }

    public class ExTextBox : System.Windows.Forms.TextBox
    {
        public event EventHandler LeaveWithChangedText;

        public bool textChanged { get; private set; }

        private string oldText = string.Empty;

        protected override void OnEnter(EventArgs e)
        {
            textChanged = false;
            oldText = Text;
            base.OnEnter(e);
        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            textChanged = oldText != Text;
            if (textChanged)
            {
                OnLeaveWithChangedText(e);
            }
        }

        protected virtual void OnLeaveWithChangedText(EventArgs e)
        {
            if (LeaveWithChangedText != null)
            {
                LeaveWithChangedText(this, e);
            }
        }
    }

    public class ExNumericUpDown : System.Windows.Forms.NumericUpDown
    {
        public event EventHandler LeaveWithChangedText;

        public bool valueChanged { get; private set; }

        private decimal oldval = 0;

        protected override void OnEnter(EventArgs e)
        {
            valueChanged = false;
            oldval = Value;
            base.OnEnter(e);
        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            valueChanged = oldval != Value;
            if (valueChanged)
            {
                OnLeaveWithChangedText(e);
            }
        }

        protected virtual void OnLeaveWithChangedText(EventArgs e)
        {
            if (LeaveWithChangedText != null)
            {
                LeaveWithChangedText(this, e);
            }
        }
    }
}